package net.lastcoder.ifserver.util;


import net.lastcoder.ifserver.Constants;

import org.apache.mina.core.buffer.IoBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * auth: WenYF
 * date: 2016/6/13 0013
 */
public class HttpUtil {
    private static final Logger Log = LoggerFactory.getLogger(HttpUtil.class);

    public static class HttpResult {
        public String message;
        public int code;
        public String content;
        public byte[] bytes;

        @Override
        public String toString() {
            return "code=" + code + ",message=" + message + ",content=" + content + ","
                    + (bytes == null ? "byte=" + null : "byte length=" + bytes.length);
        }
    }


    /**
     * @param strUrl  网络地址
     * @param method  方法：POST, GET, DELETE, PATCH...
     * @param headers 头
     * @param content 作为payload的内容
     * @return  可能为null，返回的是二进制bytes
     */
    public static HttpResult requestByte(String strUrl, String method
            , HashMap<String, String> headers, String content) {
        Log.debug("url = " + strUrl);
        try {
            URL url = asURL(strUrl);
            return request(url, method, headers, content, true);
        } catch (Exception e) {
            e.printStackTrace();
            Log.debug(e.getMessage(), e);
            return null;
        }
    }

    public static HttpResult requestByte(String strUrl, String method
            , HashMap<String, String> headers, byte[] content) {
        Log.debug("url = " + strUrl);
        try {
            URL url = asURL(strUrl);
            return request(url, method, headers, content, true);
        } catch (Exception e) {
            e.printStackTrace();
            Log.debug(e.getMessage(), e);
            return null;
        }
    }

    /**
     * @param strUrl  网络地址
     * @param method  方法：POST, GET, DELETE, PATCH...
     * @param headers 头
     * @param content 作为payload的内容
     * @return  可能为null，返回的是content
     */
    public static HttpResult requestStr(String strUrl, String method
            , HashMap<String, String> headers, String content) {
        Log.debug("url = " + strUrl);
        try {
            URL url = asURL(strUrl);
            return request(url, method, headers, content, false);
        } catch (Exception e) {
            e.printStackTrace();
            Log.error(e.getMessage(), e);
            return null;
        }
    }

    public static HttpResult requestStr(String strUrl, String method
            , HashMap<String, String> headers, byte[] content) {
        Log.debug("url = " + strUrl);
        try {
            URL url = asURL(strUrl);
            return request(url, method, headers, content, false);
        } catch (Exception e) {
            e.printStackTrace();
            Log.error(e.getMessage(), e);
            return null;
        }
    }

    private static HttpResult request(URL url, String method, HashMap<String, String> headers
            , String content, boolean requestBinary) {
        Log.debug("method = " + method + ", " + "content = " + content);
        InputStream is = null;
        OutputStream os = null;
        HttpResult hr = new HttpResult();
        try {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod(method);
            connection.setConnectTimeout(5000);

            if (method.equalsIgnoreCase("post")) {
                connection.setDoOutput(true);
            } else {
                connection.setDoOutput(false);
            }
            if (headers != null) {
                for (Map.Entry entry : headers.entrySet()) {
                    Log.debug(entry.getKey() + ":" + entry.getValue());
                    connection.setRequestProperty((String)entry.getKey(), (String)entry.getValue());
                }
            }

            connection.connect();

            if (content != null) {
                os = connection.getOutputStream();
                os.write(content.getBytes("UTF-8"));
                os.close();
            }

            hr.code = connection.getResponseCode();
            hr.message = connection.getResponseMessage();

            is = connection.getInputStream();
            if (requestBinary) {
                IoBuffer buffer = IoBuffer.allocate(1024, false);
                buffer.setAutoExpand(true);
                int b = -1;
                while ((b = is.read()) != -1) {
                    buffer.put((byte) b);
                }

                byte[] data = new byte[buffer.position()];
                System.arraycopy(buffer.array(), 0, data, 0, buffer.position());
                hr.bytes = data;
            } else {
                StringBuilder sb = new StringBuilder();
                String line;
                BufferedReader reader = getReader(is);

                int lines = 0;
                while ((line = reader.readLine()) != null) {
                    if (lines > 0) {
                        sb.append(Constants.LINE_END_CHAR);
                    }
                    sb.append(line);
                    lines++;
                }

                hr.content = sb.toString();
            }
            Log.debug("code:" + connection.getResponseCode()
                    + ",msg=" + connection.getResponseMessage());

            connection.disconnect();
        } catch (Exception e) {
            Log.error(e.getMessage(), e);
            return null;
        } finally {
            IOUtil.closeSilently(is);
            IOUtil.closeSilently(os);
        }

        return hr;
    }

    private static HttpResult request(URL url, String method, HashMap<String, String> headers
            , byte[] content, boolean requestBinary) {
        InputStream is = null;
        OutputStream os = null;
        HttpResult hr = new HttpResult();
        try {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod(method);
            connection.setConnectTimeout(5000);

            if (method.equalsIgnoreCase("post")) {
                connection.setDoOutput(true);
            } else {
                connection.setDoOutput(false);
            }
            if (headers != null) {
                for (Map.Entry entry : headers.entrySet()) {
                    Log.debug(entry.getKey() + ":" + entry.getValue());
                    connection.setRequestProperty((String)entry.getKey(), (String)entry.getValue());
                }
            }

            connection.connect();

            if (content != null) {
                os = connection.getOutputStream();
                os.write(content);
                os.close();
            }

            hr.code = connection.getResponseCode();
            hr.message = connection.getResponseMessage();

            is = connection.getInputStream();
            if (requestBinary) {
                IoBuffer buffer = IoBuffer.allocate(1024, false);
                buffer.setAutoExpand(true);
                int b = -1;
                while ((b = is.read()) != -1) {
                    buffer.put((byte) b);
                }

                byte[] data = new byte[buffer.position()];
                System.arraycopy(buffer.array(), 0, data, 0, buffer.position());
                hr.bytes = data;
            } else {
                StringBuilder sb = new StringBuilder();
                String line;
                BufferedReader reader = getReader(is);

                int lines = 0;
                while ((line = reader.readLine()) != null) {
                    if (lines > 0) {
                        sb.append(Constants.LINE_END_CHAR);
                    }
                    sb.append(line);
                    lines++;
                }

                hr.content = sb.toString();
            }
            Log.debug("code:" + connection.getResponseCode()
                    + ",msg=" + connection.getResponseMessage());

            connection.disconnect();
        } catch (Exception e) {
            Log.error(e.getMessage(), e);
            return null;
        } finally {
            IOUtil.closeSilently(is);
            IOUtil.closeSilently(os);
        }

        return hr;
    }

    public static boolean downloadFile(String strUrl, String method, HashMap<String, String> headers, String content, String filePath) {
        Log.debug("method = " + method + ", " + "content = " + content);

        FileOutputStream fos = null;
        File file = new File(filePath);
        try {
            URL url = asURL(strUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            if (!TextUtils.isEmpty(content)) {
                connection.setDoOutput(true);
            }
            connection.setRequestMethod(method);
            connection.setConnectTimeout(5000);

            if (headers != null) {
                for (Map.Entry entry : headers.entrySet()) {
                    Log.debug(entry.getKey() + ":" + entry.getValue());
                    connection.setRequestProperty((String)entry.getKey(), (String)entry.getValue());
                }
            }

            connection.connect();

            if (!TextUtils.isEmpty(content)) {
                connection.setDoOutput(true);
                OutputStream os = connection.getOutputStream();
                os.write(content.getBytes("UTF-8"));
                os.close();
            }

            int size = -1, count = 0;
            InputStream is = connection.getInputStream();
            byte[] readBuffer = new byte[1024];
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();

            fos = new FileOutputStream(file);
            while ((size = is.read(readBuffer)) != -1) {
                fos.write(readBuffer, 0, size);
                count += size;
            }

            fos.close();
            is.close();

            Log.debug("read size = " + count);
            Log.debug("code:" + connection.getResponseCode()
                    + ",msg=" + connection.getResponseMessage());

            connection.disconnect();
        } catch (Exception e) {
            Log.error(e.getMessage(), e);
            file.delete();
            return false;
        } finally {
            IOUtil.closeSilently(fos);
        }

        return true;
    }

    private static BufferedReader getReader(InputStream is) throws IOException {

        BufferedReader reader;
        reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));

        return reader;
    }

    private static URL asURL(String str) throws MalformedURLException {
        return new URL(str);
    }
}
